package cn.iocoder.yudao.module.reading.service.recordings;

import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.reading.controller.app.recordings.vo.*;
import cn.iocoder.yudao.module.reading.convert.recordings.RecordingsConvert;
import cn.iocoder.yudao.module.reading.dal.dataobject.book.BookPageDO;
import cn.iocoder.yudao.module.reading.dal.dataobject.book.PictureBookDO;
import cn.iocoder.yudao.module.reading.dal.dataobject.recording.UserRecordingDO;
import cn.iocoder.yudao.module.reading.dal.mysql.book.BookPageMapper;
import cn.iocoder.yudao.module.reading.dal.mysql.book.PictureBookMapper;
import cn.iocoder.yudao.module.reading.dal.mysql.recording.UserRecordingMapper;
import cn.iocoder.yudao.module.reading.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.reading.framework.util.StaticResourceUrlUtils;
import cn.iocoder.yudao.module.reading.service.file.ReadingFileService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 配音管理 Service 实现类
 *
 * @author 李晨
 */
@Service
@Slf4j
public class RecordingsServiceImpl implements RecordingsService {

    @Resource
    private UserRecordingMapper userRecordingMapper;
    
    @Resource
    private PictureBookMapper pictureBookMapper;
    
    @Resource
    private BookPageMapper bookPageMapper;

    @Resource
    private StaticResourceUrlUtils staticResourceUrlUtils;

    @Resource
    private ReadingFileService readingFileService;

    @Override
    public PageResult<UserRecordingRespVO> getUserRecordingList(Long userId, PageParam pageParam) {
        // 查询用户配音记录
        List<UserRecordingDO> recordingList = userRecordingMapper.selectByUserId(userId, null);

        // 分页处理
        int start = (pageParam.getPageNo() - 1) * pageParam.getPageSize();
        int end = Math.min(start + pageParam.getPageSize(), recordingList.size());
        List<UserRecordingDO> pagedList = recordingList.subList(start, end);

        // 获取绘本信息
        List<Long> bookIds = CollectionUtils.convertList(pagedList, UserRecordingDO::getBookId);
        Map<Long, PictureBookDO> bookMap = pictureBookMapper.selectByIds(bookIds)
                .stream().collect(Collectors.toMap(PictureBookDO::getId, book -> book));

        // 转换为响应VO
        List<UserRecordingRespVO> resultList = pagedList.stream()
                .map(recording -> {
                    UserRecordingRespVO vo = RecordingsConvert.INSTANCE.convertToUserRecordingRespVO(
                            recording, bookMap.get(recording.getBookId()));
                    // 将音频URL和封面URL相对路径转换为完整URL
                    vo.setAudioUrl(staticResourceUrlUtils.toFullUrl(vo.getAudioUrl()));
                    vo.setCoverUrl(staticResourceUrlUtils.toFullUrl(vo.getCoverUrl()));
                    return vo;
                })
                .collect(Collectors.toList());

        return new PageResult<>(resultList, (long) recordingList.size());
    }

    @Override
    public PageResult<UserRecordingAggregateRespVO> getUserRecordingAggregateList(Long userId, PageParam pageParam) {
        // 查询用户所有配音记录
        List<UserRecordingDO> allRecordings = userRecordingMapper.selectAggregateByUserId(userId);

        if (allRecordings.isEmpty()) {
            return new PageResult<>(new ArrayList<>(), 0L);
        }

        // 按绘本ID分组
        Map<Long, List<UserRecordingDO>> recordingsByBook = allRecordings.stream()
                .collect(Collectors.groupingBy(UserRecordingDO::getBookId));

        // 获取所有绘本信息
        List<Long> bookIds = new ArrayList<>(recordingsByBook.keySet());
        Map<Long, PictureBookDO> bookMap = pictureBookMapper.selectByIds(bookIds)
                .stream().collect(Collectors.toMap(PictureBookDO::getId, book -> book));

        // 构建聚合数据
        List<UserRecordingAggregateRespVO> aggregateList = new ArrayList<>();
        for (Map.Entry<Long, List<UserRecordingDO>> entry : recordingsByBook.entrySet()) {
            Long bookId = entry.getKey();
            List<UserRecordingDO> bookRecordings = entry.getValue();
            PictureBookDO book = bookMap.get(bookId);

            if (book != null) {
                UserRecordingAggregateRespVO aggregate = buildAggregateVO(book, bookRecordings);
                aggregateList.add(aggregate);
            }
        }

        // 按最新配音时间排序
        aggregateList.sort((a, b) -> b.getLatestRecordTime().compareTo(a.getLatestRecordTime()));

        // 分页处理
        int start = (pageParam.getPageNo() - 1) * pageParam.getPageSize();
        int end = Math.min(start + pageParam.getPageSize(), aggregateList.size());
        List<UserRecordingAggregateRespVO> pagedList = aggregateList.subList(start, end);

        return new PageResult<>(pagedList, (long) aggregateList.size());
    }

    @Override
    public UserRecordingDetailPageRespVO getUserRecordingDetailPage(Long userId, Long bookId) {
        // 校验绘本存在
        PictureBookDO book = validateBookExists(bookId);

        // 查询绘本的所有页面
        List<BookPageDO> bookPages = bookPageMapper.selectByBookId(bookId);
        if (bookPages.isEmpty()) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.BOOK_PAGE_NOT_EXISTS);
        }

        // 查询用户在该绘本的所有配音记录
        List<UserRecordingDO> userRecordings = userRecordingMapper.selectByUserIdAndBookId(userId, bookId);
        Map<Long, UserRecordingDO> recordingMap = userRecordings.stream()
                .collect(Collectors.toMap(UserRecordingDO::getPageId, r -> r, (r1, r2) -> r1));

        // 构建详情页响应
        UserRecordingDetailPageRespVO detailPage = new UserRecordingDetailPageRespVO();
        detailPage.setBookId(book.getId());
        detailPage.setBookTitle(book.getTitle());
        // 将封面相对路径转换为完整URL
        detailPage.setCoverUrl(staticResourceUrlUtils.toFullUrl(book.getCover()));
        detailPage.setTotalPages(book.getPages());

        // 构建页面配音列表
        List<UserRecordingDetailPageRespVO.PageRecordingVO> pageRecordings = new ArrayList<>();
        for (BookPageDO page : bookPages) {
            UserRecordingDetailPageRespVO.PageRecordingVO pageRecording = buildPageRecordingVO(page, recordingMap.get(page.getId()));
            pageRecordings.add(pageRecording);
        }
        detailPage.setPageRecordings(pageRecordings);

        // 计算统计信息
        long recordedCount = pageRecordings.stream().filter(UserRecordingDetailPageRespVO.PageRecordingVO::getHasRecording).count();
        detailPage.setRecordedPages((int) recordedCount);

        if (book.getPages() != null && book.getPages() > 0) {
            int completionPercentage = (int) ((recordedCount * 100) / book.getPages());
            detailPage.setCompletionPercentage(completionPercentage);
        } else {
            detailPage.setCompletionPercentage(0);
        }

        // 是否全部可分享
        boolean allShareable = userRecordings.stream()
                .allMatch(r -> r.getIsShareable() != null && r.getIsShareable());
        detailPage.setAllShareable(allShareable && !userRecordings.isEmpty());

        return detailPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setBookRecordingsPublic(Long userId, Long bookId, Boolean isPublic) {
        // 校验绘本存在
        validateBookExists(bookId);

        // 查询用户在该绘本的配音记录
        List<UserRecordingDO> userRecordings = userRecordingMapper.selectByUserIdAndBookId(userId, bookId);
        if (userRecordings.isEmpty()) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.USER_RECORDING_NOT_EXISTS);
        }

        // 批量更新公开状态
        int updateCount = userRecordingMapper.updateBookRecordingsPublicStatus(userId, bookId, isPublic);

        log.info("批量设置绘本配音公开状态成功，用户ID: {}, 绘本ID: {}, 公开状态: {}, 更新数量: {}",
                userId, bookId, isPublic, updateCount);
    }

    @Override
    public UserRecordingShareRespVO generateBookRecordingShare(Long userId, Long bookId) {
        // 校验绘本存在
        PictureBookDO book = validateBookExists(bookId);

        // 查询用户在该绘本的配音记录
        List<UserRecordingDO> userRecordings = userRecordingMapper.selectByUserIdAndBookId(userId, bookId);
        if (userRecordings.isEmpty()) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.USER_RECORDING_NOT_EXISTS);
        }

        // 检查是否有公开的配音记录
        boolean hasPublicRecordings = userRecordings.stream()
                .anyMatch(r -> r.getIsShareable() != null && r.getIsShareable());
        if (!hasPublicRecordings) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.USER_RECORDING_NOT_SHAREABLE);
        }

        // 构建分享信息
        UserRecordingShareRespVO shareInfo = new UserRecordingShareRespVO();
        shareInfo.setBookId(bookId);

        // 生成分享文本
        int recordingCount = userRecordings.size();
        int totalDuration = userRecordings.stream()
                .mapToInt(r -> r.getDuration() != null ? r.getDuration() : 0)
                .sum();
        int minutes = totalDuration / 60;
        int seconds = totalDuration % 60;

        String shareText = String.format("我完成了《%s》的配音，共%d页，总时长%d分%d秒，快来听听吧！",
                book.getTitle(), recordingCount, minutes, seconds);
        shareInfo.setShareText(shareText);

        // 生成分享标题和描述
        shareInfo.setShareTitle("我的配音作品 - " + book.getTitle());
        shareInfo.setShareDescription(String.format("完成了%d页配音，总时长%d分%d秒", recordingCount, minutes, seconds));

        // 生成分享链接（这里使用简单的格式，实际项目中可能需要更复杂的逻辑）
        String shareUrl = String.format("https://example.com/recording/share/%d/%d", userId, bookId);
        shareInfo.setShareUrl(shareUrl);

        // 生成二维码URL（这里使用占位符，实际项目中需要调用二维码生成服务）
        String qrCodeUrl = String.format("https://example.com/qrcode/recording_%d_%d.png", userId, bookId);
        shareInfo.setQrCodeUrl(qrCodeUrl);

        // 分享图片URL（这里使用绘本封面作为占位符，实际项目中可能需要生成专门的分享图片）
        shareInfo.setShareImage(book.getCover());

        log.info("生成绘本配音分享信息成功，用户ID: {}, 绘本ID: {}, 配音数量: {}", userId, bookId, recordingCount);

        return shareInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveUserRecording(Long userId, UserRecordingCreateReqVO reqVO) {
        // 校验绘本存在
        PictureBookDO book = validateBookExists(reqVO.getBookId());

        // 校验页面存在
        BookPageDO page = validatePageExists(reqVO.getBookId(), reqVO.getPageNumber());

        // 将完整URL转换为相对路径存储到数据库
        String relativeAudioUrl = staticResourceUrlUtils.toRelativePath(reqVO.getAudioUrl());

        // 检查是否已有该页面的配音记录
        UserRecordingDO existingRecording = userRecordingMapper.selectByUserIdAndPageId(userId, page.getId());
        if (existingRecording != null) {
            // 更新现有记录
            existingRecording.setAudioUrl(relativeAudioUrl);
            existingRecording.setDuration(reqVO.getDuration());
            userRecordingMapper.updateById(existingRecording);
            log.info("更新用户配音记录成功，用户ID: {}, 页面ID: {}", userId, page.getId());
        } else {
            // 创建新记录
            UserRecordingDO recordingDO = RecordingsConvert.INSTANCE.convertToUserRecordingDO(reqVO);
            recordingDO.setUserId(userId);
            recordingDO.setPageId(page.getId());
            // 设置页码
            recordingDO.setPageNumber(reqVO.getPageNumber());
            // 确保保存的是相对路径
            recordingDO.setAudioUrl(relativeAudioUrl);
            userRecordingMapper.insert(recordingDO);
            log.info("保存用户配音记录成功，用户ID: {}, 页面ID: {}", userId, page.getId());
        }
    }

    @Override
    public UserRecordingDetailRespVO getUserRecordingByPage(Long userId, Long pageId) {
        log.info("查询用户录音记录，用户ID: {}, 页面ID: {}", userId, pageId);

        UserRecordingDO recording = userRecordingMapper.selectByUserIdAndPageId(userId, pageId);

        if (recording == null) {
            log.info("用户{}在页面{}没有录音记录", userId, pageId);
            return null;
        }

        log.info("找到用户录音记录: {}", recording);
        UserRecordingDetailRespVO result = RecordingsConvert.INSTANCE.convertToDetailRespVO(recording);
        // 将音频URL相对路径转换为完整URL
        result.setAudioUrl(staticResourceUrlUtils.toFullUrl(result.getAudioUrl()));
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRecording(Long userId, Long recordingId) {
        // 校验配音记录存在且属于当前用户
        UserRecordingDO recording = validateRecordingExists(userId, recordingId);
        
        // 软删除配音记录
        userRecordingMapper.softDeleteByUserIdAndId(userId, recordingId);
        
        log.info("删除配音记录成功，用户ID: {}, 配音记录ID: {}", userId, recordingId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void shareRecording(Long userId, Long recordingId) {
        // 校验配音记录存在且属于当前用户
        UserRecordingDO recording = validateRecordingExists(userId, recordingId);
        
        // 设置为可分享
        recording.setIsShareable(true);
        userRecordingMapper.updateById(recording);
        
        log.info("分享配音记录成功，用户ID: {}, 配音记录ID: {}", userId, recordingId);
    }

    @Override
    public PageAudioStatusRespVO getPageAudioStatus(Long userId, Long pageId) {
        // 获取页面信息
        BookPageDO page = bookPageMapper.selectById(pageId);
        if (page == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.BOOK_PAGE_NOT_EXISTS);
        }
        
        // 检查用户录制音频
        UserRecordingDO userRecording = userRecordingMapper.selectByUserIdAndPageId(userId, pageId);
        
        PageAudioStatusRespVO result = new PageAudioStatusRespVO();
        result.setPageId(pageId);
        result.setHasOfficialAudio(StrUtil.isNotBlank(page.getOfficialAudioUrl()));
        result.setHasUserRecording(userRecording != null);
        
        if (result.getHasOfficialAudio()) {
            result.setOfficialAudioUrl(page.getOfficialAudioUrl());
        }
        
        if (result.getHasUserRecording()) {
            result.setUserRecordingUrl(userRecording.getAudioUrl());
            result.setPreferredSource("user");
        } else if (result.getHasOfficialAudio()) {
            result.setPreferredSource("official");
        }
        
        return result;
    }

    /**
     * 校验绘本存在
     */
    private PictureBookDO validateBookExists(Long bookId) {
        PictureBookDO book = pictureBookMapper.selectById(bookId);
        if (book == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.PICTURE_BOOK_NOT_EXISTS);
        }
        return book;
    }

    /**
     * 校验页面存在
     */
    private BookPageDO validatePageExists(Long bookId, Integer pageNumber) {
        BookPageDO page = bookPageMapper.selectByBookIdAndPageNumber(bookId, pageNumber);
        if (page == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.BOOK_PAGE_NOT_EXISTS);
        }
        return page;
    }

    /**
     * 校验配音记录存在且属于当前用户
     */
    private UserRecordingDO validateRecordingExists(Long userId, Long recordingId) {
        UserRecordingDO recording = userRecordingMapper.selectById(recordingId);
        if (recording == null || !recording.getUserId().equals(userId)) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.USER_RECORDING_NOT_EXISTS);
        }
        return recording;
    }

    /**
     * 构建聚合配音VO
     */
    private UserRecordingAggregateRespVO buildAggregateVO(PictureBookDO book, List<UserRecordingDO> recordings) {
        UserRecordingAggregateRespVO aggregate = new UserRecordingAggregateRespVO();

        // 基本信息
        aggregate.setBookId(book.getId());
        aggregate.setBookTitle(book.getTitle());
        // 将封面相对路径转换为完整URL
        aggregate.setCoverUrl(staticResourceUrlUtils.toFullUrl(book.getCover()));
        aggregate.setTotalPages(book.getPages());

        // 统计信息
        aggregate.setRecordingCount(recordings.size());

        // 计算总时长
        int totalDuration = recordings.stream()
                .mapToInt(r -> r.getDuration() != null ? r.getDuration() : 0)
                .sum();
        aggregate.setTotalDuration(totalDuration);

        // 格式化总时长
        int minutes = totalDuration / 60;
        int seconds = totalDuration % 60;
        aggregate.setFormattedTotalDuration(String.format("%02d:%02d", minutes, seconds));

        // 计算平均评分
        OptionalDouble avgScore = recordings.stream()
                .filter(r -> r.getScore() != null)
                .mapToInt(UserRecordingDO::getScore)
                .average();
        aggregate.setAverageScore(avgScore.isPresent() ? (int) Math.round(avgScore.getAsDouble()) : null);

        // 最新配音时间
        LocalDateTime latestTime = recordings.stream()
                .map(UserRecordingDO::getCreateTime)
                .max(LocalDateTime::compareTo)
                .orElse(LocalDateTime.now());
        aggregate.setLatestRecordTime(latestTime);

        // 是否全部可分享
        boolean allShareable = recordings.stream()
                .allMatch(r -> r.getIsShareable() != null && r.getIsShareable());
        aggregate.setAllShareable(allShareable);

        // 计算已配音页数（去重）
        Set<Integer> recordedPageNumbers = recordings.stream()
                .map(UserRecordingDO::getPageNumber)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        aggregate.setRecordedPages(recordedPageNumbers.size());

        // 计算完成度百分比
        if (book.getPages() != null && book.getPages() > 0) {
            int completionPercentage = (recordedPageNumbers.size() * 100) / book.getPages();
            aggregate.setCompletionPercentage(completionPercentage);
        } else {
            aggregate.setCompletionPercentage(0);
        }

        return aggregate;
    }

    /**
     * 构建页面配音VO
     */
    private UserRecordingDetailPageRespVO.PageRecordingVO buildPageRecordingVO(BookPageDO page, UserRecordingDO recording) {
        UserRecordingDetailPageRespVO.PageRecordingVO pageRecording = new UserRecordingDetailPageRespVO.PageRecordingVO();

        // 页面基本信息
        pageRecording.setPageId(page.getId());
        pageRecording.setPageNumber(page.getPageNumber());
        // 将页面图片相对路径转换为完整URL
        pageRecording.setImageUrl(staticResourceUrlUtils.toFullUrl(page.getImageUrl()));
        pageRecording.setTextContent(page.getTextContent());

        // 配音信息
        if (recording != null) {
            pageRecording.setHasRecording(true);
            pageRecording.setRecordingId(recording.getId());
            // 将相对路径转换为完整URL
            pageRecording.setAudioUrl(staticResourceUrlUtils.toFullUrl(recording.getAudioUrl()));
            pageRecording.setDuration(recording.getDuration());
            pageRecording.setScore(recording.getScore());
            pageRecording.setIsShareable(recording.getIsShareable());
            pageRecording.setRecordTime(recording.getCreateTime());
            pageRecording.setRecordingQuality(recording.getRecordingQuality());

            // 格式化时长
            if (recording.getDuration() != null) {
                int minutes = recording.getDuration() / 60;
                int seconds = recording.getDuration() % 60;
                pageRecording.setFormattedDuration(String.format("%02d:%02d", minutes, seconds));
            }
        } else {
            pageRecording.setHasRecording(false);
            pageRecording.setRecordingId(null);
            pageRecording.setAudioUrl(null);
            pageRecording.setDuration(null);
            pageRecording.setFormattedDuration(null);
            pageRecording.setScore(null);
            pageRecording.setIsShareable(false);
            pageRecording.setRecordTime(null);
            pageRecording.setRecordingQuality(null);
        }

        return pageRecording;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBookRecordings(Long userId, Long bookId) {
        log.info("删除用户绘本配音记录，用户ID: {}, 绘本ID: {}", userId, bookId);

        // 查询该用户该绘本的所有配音记录
        List<UserRecordingDO> recordings = userRecordingMapper.selectByUserIdAndBookId(userId, bookId);

        if (recordings.isEmpty()) {
            log.info("用户{}的绘本{}没有配音记录", userId, bookId);
            return;
        }

        log.info("找到{}条配音记录需要删除", recordings.size());

        // 删除物理文件
        for (UserRecordingDO recording : recordings) {
            if (StrUtil.isNotBlank(recording.getAudioUrl())) {
                try {
                    boolean deleted = readingFileService.deleteFile(recording.getAudioUrl());
                    if (deleted) {
                        log.info("删除配音文件成功: {}", recording.getAudioUrl());
                    } else {
                        log.warn("删除配音文件失败: {}", recording.getAudioUrl());
                    }
                } catch (Exception e) {
                    log.error("删除配音文件异常: {}", recording.getAudioUrl(), e);
                    // 继续删除其他文件，不因为单个文件删除失败而中断整个流程
                }
            }
        }

        // 软删除数据库记录
        for (UserRecordingDO recording : recordings) {
            userRecordingMapper.softDeleteByUserIdAndId(userId, recording.getId());
        }

        log.info("删除用户绘本配音记录完成，用户ID: {}, 绘本ID: {}, 删除数量: {}", userId, bookId, recordings.size());
    }

}
